#pragma once
#include <pthread.h>
#include <vector>
#include <semaphore.h>

using namespace std;

pthread_mutex_t p_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t c_mutex = PTHREAD_MUTEX_INITIALIZER;

template<class T>
class RingQueue
{

public:
    RingQueue(int cap)
        :_cap(cap)
        ,rq(cap)
    {
       sem_init(&psem, 0, cap);
       sem_init(&csem, 0, 0);
    }

    //申请资源，sem做--操作
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }

    //释放资源，sem做++操作
    void V(sem_t &sem)
    {
        sem_post(&sem);
    }

    void Push(const T& in)
    {
        P(psem);
        pthread_mutex_lock(&p_mutex);

        rq[pindex++] = in;
        pindex %= _cap;

        pthread_mutex_unlock(&p_mutex);
        V(csem);        
    }

    void Pop(T& out)
    {
        P(csem);
        pthread_mutex_lock(&c_mutex);

        out = rq[cindex++]; 
        cindex %= _cap;

        pthread_mutex_unlock(&c_mutex);
        V(psem);
    }

    ~RingQueue()
    {
        sem_destroy(&psem);
        sem_destroy(&csem);
    }

private:
    int _cap;
    vector<T> rq;  //存放资源

    sem_t psem;
    sem_t csem;

    int pindex = 0;
    int cindex = 0;
};